package de.codi.structural;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;

import com.googlecode.rockit.app.RockItAPI;
import com.googlecode.rockit.app.result.RockItResult;
import com.googlecode.rockit.exception.ReadOrWriteToFileException;

import de.codi.exception.CodiException;
import de.codi.read.Storage;
import de.unima.alcomox.mapping.Mapping;


public class RockItStandardMatcher
{

    public RockItStandardMatcher()
    {
    }


    public Mapping match(ArrayList<String[]> conceptSimilarityValues, ArrayList<String[]> objectPropertySimilarityValues, ArrayList<String[]> datatypePropertySimilarityValues) throws CodiException
    {
        // Generate Models (Considers Settings in CODISettings)
        // Model model = (new ModelGenerator()).generateModel();

        // Adds GroundValues
        List<String> groundPredicates = new ArrayList<String>();

        GroundValueGenerator generator1 = new GroundValueGenerator(Storage.source);
        GroundValueGenerator generator2 = new GroundValueGenerator(Storage.target);

        for(String predicate : getObservedPredicates()) {
            if(predicate.endsWith("1")) {
                generator1.addGroundValues(groundPredicates, predicate);
            } else if(predicate.endsWith("2")) {
                generator2.addGroundValues(groundPredicates, predicate);
            } else if(predicate.equals(StructuralConstants.CMAP_CONFIDENCE)) {
                addMapping(groundPredicates, predicate, conceptSimilarityValues);
            } else if(predicate.equals(StructuralConstants.PMAP_CONFIDENCE)) {
                ArrayList<String[]> stringVal = new ArrayList<String[]>();
                if(objectPropertySimilarityValues != null)
                    stringVal.addAll(objectPropertySimilarityValues);
                if(datatypePropertySimilarityValues != null)
                    stringVal.addAll(datatypePropertySimilarityValues);
                addMapping(groundPredicates, predicate, stringVal);
            }
        }

        // solve the model

        List<RockItResult> result = new ArrayList<>();

        try {

            StringBuilder evidenceContent = new StringBuilder();
            for(String x : groundPredicates) {
                evidenceContent.append(x + System.lineSeparator());
            }

            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("evidence.db"), "UTF-8"));
            out.write(evidenceContent.toString());
            out.close();

            RockItAPI rockIt = new RockItAPI("rockit-0.5.276.properties");
            result = rockIt.doMapState("prog.mln", "evidence.db");

        } catch(IOException e) {
            e.printStackTrace();
            throw new CodiException("Could not store the rockIt model.", e);
        } catch(ReadOrWriteToFileException e) {
            e.printStackTrace();
            throw new CodiException("Could not initiate RockIt.", e);
        } catch(Exception e) {
            e.printStackTrace();
            throw new CodiException("RockIt crashed...", e);

        }

        AlignmentGenerator alignmentGen = new AlignmentGenerator();
        return alignmentGen.convertToMapping(result);

    }


    private void addMapping(List<String> groundPredicates, String predicate, ArrayList<String[]> similarityValues)
    {
        for(String[] sim : similarityValues) {
            groundPredicates.add(predicate + "(\"" + sim[0] + "\", \"" + sim[1] + "\", " + sim[2] + ")");
        }

    }


    private List<String> getObservedPredicates()
    {
        List<String> predicates = new ArrayList<String>();

        predicates.add("class1");
        predicates.add("class2");

        predicates.add("prop1");
        predicates.add("prop2");

        predicates.add("subsumes1");
        predicates.add("subsumes2");

        predicates.add("disjoint1");
        predicates.add("disjoint2");

        predicates.add("domainsub1");
        predicates.add("domainsub2");

        predicates.add("domainsup1");
        predicates.add("domainsup2");

        predicates.add("domaindis1");
        predicates.add("domaindis2");

        predicates.add("rangesub1");
        predicates.add("rangesub2");

        predicates.add("rangesup1");
        predicates.add("rangesup2");

        predicates.add("rangedis1");
        predicates.add("rangedis2");

        predicates.add("pmapConfidence");
        predicates.add("cmapConfidence");

        return predicates;
    }
}
